<?php
/**
 * Celebrio GoogleNews
 *
 * @copyright  Copyright (c) 2011 Celebrio Software
 * @package    GoogleAPI
 */
namespace Celebrio\GoogleAPI\GoogleNews;

use Nette\Object;

use Celebrio\Util\CacheName;
use Nette\Caching\Cache;
use \dibi;

class GoogleNewsReader extends Object {
    
    const HALF_HOUR = 1800;
    const FIVE_MINUTES = 300;
    private $countryCode;
    private static $supportedCountryCodes = array (
	"cs_cz", "us" // Slovak will not be accesible because there is no google news for that country
    );
    private $links = array();
    /*private $topStories = array (
	"cs_cz" => "http://news.google.cz/news?pz=1&cf=all&ned=cs_cz&hl=cs&output=rss",
        "us" => "http://news.google.com/news?pz=1&cf=all&ned=us&hl=en&output=rss"
    );
    private $world = array (
	"cs_cz" => "http://news.google.cz/news?pz=1&cf=all&ned=cs_cz&hl=cs&topic=w&output=rss",
        "us" => "http://news.google.com/news?pz=1&cf=all&ned=us&hl=en&topic=w&output=rss"
    );
    private $entertainment = array (
	"cs_cz" => "http://news.google.cz/news?pz=1&cf=all&ned=cs_cz&hl=cs&topic=e&output=rss",
        "us" => "http://news.google.com/news?pz=1&cf=all&ned=us&hl=en&topic=e&output=rss"
    );
    private $sports = array (
	"cs_cz" => "http://news.google.cz/news?pz=1&cf=all&ned=cs_cz&hl=cs&topic=s&output=rss",
        "us" => "http://news.google.com/news?pz=1&cf=all&ned=us&hl=en&topic=s&output=rss"
    );*/

    public function __construct($countryCode) {
	$countryCode = \strtolower($countryCode);
        $this->makeLocalizedLinks($countryCode);
	/*if(!self::isCountrySupported($countryCode)) {
	    throw new \InvalidStateException("Unsupported country code.");
	    return;
	}*/
	$this->countryCode = $countryCode;
    }

    private function getResult($url) {
        $cache = $this->getCachedUrl();
        $urlHash = sha1($url);
        $offset = $cache->offsetGet($urlHash);
        $time = \time();
        if ($offset === null) { //If offset is null it means that service is called for the first time or cache expired (maybe it could be store for long time and than it will never expire)
            $document = @simplexml_load_file($url);
            if (!$document) {
                throw new \InvalidStateException("Could not retrieve data from Google News server.");
            }
            $xml = $document->channel;
            $xmlData = $this->parseNewsXml($xml);
            $data = array("created" => $time, "last_call" => $time, "data" => $xmlData);
            $this->saveCache($urlHash, $data);
            return $xmlData;
        } else {
            if(($offset["created"] <= ($time - self::HALF_HOUR )) && ($offset["last_call"] <= ($time - self::FIVE_MINUTES))) {
                $document = @simplexml_load_file($url);
                if(!$document) {
                    $offset["last_call"] = $time;
                    $cache->save($urlHash, $offset);
                    return $offset["data"];
                } else {
                    $xml = $document->channel;
                    $xmlData = $this->parseNewsXml($xml);
                    $data = array("created" => $time, "last_call" => $time, "data" => $xmlData);
                    $this->saveCache($urlHash, $data);
                    return $xmlData;
                }
            } else {
                return $offset["data"];
            }
        }
    }
    
    private function parseNewsXml($xml) {
        $result = array();
        $result["title"] = $xml->title->__toString();
	$result["copyright"] = $xml->copyright->__toString();
	$result["pubdate"] = $xml->pubDate->__toString();
	$result["googlelogo"] = $xml->image->url->__toString();
	$result["items"] = array ();
	foreach($xml->item as $item){
	    $result["items"][] = array (
                "guid" => $this->getGuidCluster($item->guid->__toString()),
		"title" => $item->title->__toString(),
		"link" => $item->link->__toString(),
		"category" => $item->category->__toString(),
		"pubdate" => $item->pubDate->__toString(),
		"description" => strip_tags($item->description->__toString(),"<a><img><b><br><nobr><table><td><tr>")
	    );
	}//"description" => strip_tags($item->description,"<a><b><br><nobr>")
	//"description" => str_replace('size="-2"',"",str_replace('size="-1"',"",str_replace("font-size:85%;","",$item->description)))
	unset($xml);
	return $result;
    }
    
    private function getGuidCluster($guid) {
        $equalPos = strpos($guid, "=");
        $id = substr($guid, $equalPos+1);
        return $id;
    }

    public function rateArticle($feed, $guid) {
        $idLanguage = $this->manageLanguage($this->countryCode);
        $this->manageArticle($feed, $guid, $idLanguage);
    }
    
    public function getRatedArticles() {
        $result = dibi::query("SELECT [feed], [counter], [guid] FROM [news_app_top_stories] AS stories JOIN [languages] ON stories.[id_language] = languages.[id_language] WHERE language='" . $this->countryCode . "' ORDER BY [counter] DESC LIMIT 10")->fetchAll();
        $articles = array();
        foreach($result as $item) {
            $art = array();
            $art["guid"] = $item->guid;
            $art["rating"] = $item->counter;
            $art["feed"] = html_entity_decode($item->feed);
            $articles[] = $art;
        }
        return $articles;
    }
    
    private function manageLanguage($countryCode) {
        $id = dibi::select("id_language")->from("languages")->where("language=%s", $countryCode)->fetch();
        if(!$id) {
            $args = array("language" => $countryCode);
            dibi::insert("languages", $args)->execute();
            $id = dibi::getInsertId();
            return $id;
        } else {
            return $id["id_language"];
        }
    }
    
    private function manageArticle($feed, $guid, $idLanguage) {
        $fluent = dibi::query("UPDATE [news_app_top_stories] SET counter=counter+1 WHERE guid=" . $guid);
        $affected = dibi::getAffectedRows();
        if($affected < 1) {
            $args = array(
                "guid" => $guid,
                "feed" => $feed,
                "id_language" => $idLanguage
            );
            dibi::insert("news_app_top_stories", $args)->execute();
        }
    }


    public function getTopStories(){
        return $this->getResult($this->links["topStories"]);
    }

    public function getWorld(){
        return $this->getResult($this->links["world"]);
    }

    public function getEntertainment(){
        return $this->getResult($this->links["entertainment"]);
    }

    public function getSports(){
        return $this->getResult($this->links["sports"]);
    }

    /**
     * checks whether a country code is supported
     * @param string $countryCode "e.g. cs"
     * @return boolean Returns TRUE on success or FALSE on failure.
     */
    public static function isCountrySupported($countryCode) {
	$countryCode = \strtolower($countryCode);
	return \in_array($countryCode, self::$supportedCountryCodes);
    }
    
    private function makeLocalizedLinks($localization) {
        $this->links = array();
        $this->links['topStories'] = "http://news.google.com/news?pz=1&cf=all&ned=". $localization ."&hl=". $localization ."&output=rss";
        $this->links['world'] = "http://news.google.com/news?pz=1&cf=all&ned=". $localization ."&hl=". $localization ."&topic=w&output=rss";
        $this->links['entertainment'] = "http://news.google.com/news?pz=1&cf=all&ned=". $localization ."&hl=". $localization ."&topic=e&output=rss";
        $this->links['sports'] = "http://news.google.com/news?pz=1&cf=all&ned=". $localization ."&hl=". $localization ."&topic=s&output=rss";
    }
    
    private function saveCache($hashedUrl, $data, $dp = null) {
        $cache = CacheName::generate($this);
        $cache->save($hashedUrl, $data, $dp);
    }
    
    //TODO: lazy getter would be better?
    private function getCachedUrl() {
        $cache = CacheName::generate($this);
        return $cache;
    }

}